/**
 * @file DHT11.c
 * @brief 温湿度传感器
 *
 * @author 钟涛
 *
 * @date 2022-05-08
 *
 * @copyright 海南大学 - 追光者
 */

#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
#include "hw_delay.h"
#include "app_main.h"

#define DBG_TAG "DHT11"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#define __DHT11_IO_IN                   rt_pin_mode(DHT11_PIN, PIN_MODE_INPUT_PULLUP)
#define __DHT11_DQ_IN                   rt_pin_read(DHT11_PIN)
#define delay_us                        hw_delay_us

void DHT11_Rst(void)
{
    rt_pin_mode(DHT11_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(DHT11_PIN, PIN_LOW);
    delay_ms(20);
    rt_pin_write(DHT11_PIN, PIN_HIGH);
    delay_us(30);
}

int DHT11_Check(void)
{
    uint8_t retry = 0;
    __DHT11_IO_IN;

    while (__DHT11_DQ_IN && retry < 100) //DHT11会拉低40~80us
    {
        if (++retry >= 100)
            goto exit;

        delay_us(1);
    };

    retry = 0;
    while (!__DHT11_DQ_IN && retry < 100) //DHT11拉低后会再次拉高40~80us
    {
        if (++retry >= 100)
            goto exit;

        delay_us(5);
    };

    return 0;

    exit:
    LOG_D("DHT11 check fail!");
    return 1;
}

uint8_t DHT11_Read_Bit(void)
{
    uint8_t retry = 0;

    while (__DHT11_DQ_IN && retry < 100) //等待变为低电平
    {
        retry++;
        delay_us(5);
    }

    retry = 0;
    while (!__DHT11_DQ_IN && retry < 100) //等待变高电平
    {
        retry++;
        delay_us(5);
    }

    delay_us(40); //等待40us
    if (__DHT11_DQ_IN)
        return 1;
    else
        return 0;
}
//从DHT11读取一个字节
//返回值：读到的数据
uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, dat;
    dat = 0;
    for (i = 0; i < 8; i++)
    {
        dat <<= 1;
        dat |= DHT11_Read_Bit();
    }
    return dat;
}

/**
 * 读取温湿度
 * @param temperature 温度保存指针
 * @param humidity 湿度保存指针
 * @return 成功则返回0
 */
uint8_t DHT11_Read(uint8_t *temperature, uint8_t *humidity)
{
    uint8_t buff[5];
    uint8_t i;
    DHT11_Rst();
    if (DHT11_Check() == 0)
    {
        for (i = 0; i < 5; i++) //读取40位数据
        {
            buff[i] = DHT11_Read_Byte();
        }
        for (i = 0; i < 5; i++) //读取40位数据
        {
            LOG_D("buff[%d]: %02X", i, buff[i]);
        }
        if ((buff[0] + buff[1] + buff[2] + buff[3]) == buff[4])
        {
            *humidity = buff[0];
            *temperature = buff[2];
            return 0;
        }
    }

    return 1;
}

/**
 * 测试读取温湿度传感器
 * @return 成功则返回0
 */
int test_DHT11(void)
{
    uint8_t temperature = 0, humidity = 0;
    if (DHT11_Read(&temperature, &humidity))
    {
        LOG_E("Read DHT11 fail!");
        return 1;
    }
    else
    {
        LOG_I("temperature: %u °C, humidity: %u %%", temperature, humidity);
    }
    return 0;
}
MSH_CMD_EXPORT(test_DHT11, test DHT11);

/**
 * 初始化DHT11
 * @return 成功则返回0
 */
int DHT11_init(void)
{
    DHT11_Rst();

    return DHT11_Check();
}
INIT_DEVICE_EXPORT(DHT11_init);
